﻿using System;
using System.Linq;
using CommonLib;
using CommonLib.Materials;
using CommonLib.Geometry;
using CommonLib.Engine;
using CommonLib.Primitives;
using Microsoft.DirectX;
using CommonLib.Common;
namespace PhongShading
{
// ReSharper disable UnusedMember.Global
    public class PluginPhong : IPluginShading
// ReSharper restore UnusedMember.Global
    {
        public string Description { get { return "Закраска Фонга"; } }
        public string ID { get { return "89004AE6-A2BC-46E2-9425-9904A06A2713"; }
        }        
        public Color Shade(Ray ray, Scene scn)
        {
            Intersections intersections = Utilities.GetIntersections(ray, scn);
            HitInfo firstIntersection = intersections.GetBestIntersection();
            if (firstIntersection == null)
                return scn.Background;
            var clr = new Color();
            var v = new Vector3(ray.Dir.X * (-1), ray.Dir.Y * (-1), ray.Dir.Z * (-1)); //вектор, направленный в сторону камеры
            v.Normalize();
            var hitObj = firstIntersection.HitObj as Shape;            
// ReSharper disable PossibleNullReferenceException
            Point3D p = Utilities.GetTransformPoint(firstIntersection.HitPoint,hitObj.TransformMatrix);
// ReSharper restore PossibleNullReferenceException
            Vector3 normal = Utilities.GetTransformVector(firstIntersection.HitNormal, hitObj.InvTransformMatrix);
            normal.Normalize();
            clr.Add(hitObj.MaterialShape.AmbientColor);
            //начинаем строить тени
            var feeler = new Ray {Start = new Point3D(p.X + 0.01f*v.X, p.Y + 0.01f*v.Y, p.Z + 0.01f*v.Z)};
                //щуп теней исходит из точки удара в направлении источников света
            foreach (var light in scn.Lights)
            {
                feeler.Dir = new Vector3(light.Position.X - p.X, light.Position.Y - p.Y, light.Position.Z - p.Z);
                if (Utilities.IsShadow(feeler, scn))
                    continue;
                var s = feeler.Dir;
                s.Normalize();
                float mDots = Vector3.Dot(s, normal);//коэффициент ламберта
                if (mDots > 0)
                {
                    var diffuse = hitObj.MaterialShape.DiffuseColor.Multiply(light.Color).Multiply(mDots);
                    clr.Add(diffuse);
                }
                var temp = new Vector3(v.X + s.X, v.Y + s.Y, v.Z + s.Z);
                temp.Normalize();
                var mDoth = Vector3.Dot(temp, normal);
                if (mDoth > 0)
                {
                    var phong = (float)Math.Pow(mDoth, hitObj.MaterialShape.SpecularExponent);//коэф. Фонга
                    var specColor = hitObj.MaterialShape.SpecularColor.Multiply(light.Color).Multiply(phong);
                    clr.Add(specColor);
                }
            }
            return clr;
        }
    }
}
